# do with fisco-bcos
import os
import json
import sys
# sys.path.append("../python-sdk/")
sdk_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "../python-sdk/"))
print("SDK Path:", sdk_path)
# Append the absolute path to sys.path
sys.path.append(sdk_path)
from client.bcoserror import ( 
    BcosException,
)
from client.bcosclient import BcosClient
from console_utils.cmd_account import CmdAccount
from eth_account.account import Account
from eth_utils.hexadecimal import encode_hex
from eth_utils import to_checksum_address
from client.stattool import StatTool
from client.common import common
from client.signer_impl import Signer_ECDSA
# 添加DatatypeParser导入
from client.datatype_parser import DatatypeParser

class MyCmdAccount(CmdAccount):

    #根据用户名创建链上EOA账号
    def create_ecdsa_account_task(self, name):
        ac = Account.create(name) #将用户名作为随机值创建一个新的EOA账户
        # print("new address :\t", ac.address)
        # print("new privkey :\t", encode_hex(ac.key))
        # print("new pubkey :\t", ac.publickey)
        #password暂时未使用，这里可以考虑使用Account.encrypt()方法利用用户password将私钥加密存储,该方法返回一个json对象

        return {"status":"0", "address":ac.address, "privatekey":encode_hex(ac.key),"publickey":ac.publickey}

    #根据用户私钥加载链上用户信息
    def load_ecdsa_account(self, privkey):
        try:
            ac = Signer_ECDSA.from_privkey(privkey)
            return {"status": "0", "statusMsg": "load sucess", "address":ac.address, "privatekey":encode_hex(ac.key),"publickey":ac.publickey}
        except Exception as e:
            raise BcosException(
                ("load account info failed," " error info: {}!").format(e)
            )

# 负责调用bcos
class BcosApi:
    def __init__(self):
        self.cmd_account = MyCmdAccount()
        self.client = BcosClient()
        # 初始化DatatypeParser
        self.data_parser = DatatypeParser()
        
        # 加载单一合约ProductTraceability的ABI和地址
        self.load_contract_config()
        
        # # 设置DatatypeParser的ABI - 这一步很重要！
        if self.contract_abi:
            self.data_parser.set_abi(self.contract_abi)
            print("DatatypeParser ABI设置成功")
            # 调试：打印可用的函数
            print(f"可用函数: {list(self.data_parser.func_abi_map_by_name.keys())}")
        else:
            print("警告: 无法为DatatypeParser设置ABI")

        print(f"ProductTraceability合约地址: {self.contract_address}")
        print(f"ProductTraceability ABI loaded: {self.contract_abi is not None}")
    
    def load_contract_config(self):
        """从product_traceability_config.json配置文件加载合约配置"""
        try:
            config_path = os.path.join(os.path.dirname(__file__), "../product_traceability_config.json")
            
            if os.path.exists(config_path):
                with open(config_path, 'r', encoding='utf-8') as f:
                    contracts_config = json.load(f)
                
                # 从ProductTraceability配置加载
                if "ProductTraceability" in contracts_config:
                    self.contract_address = contracts_config["ProductTraceability"].get("address", "")
                    abi_file = contracts_config["ProductTraceability"].get("abi_file", "")
                    
                    if abi_file:
                        # 如果是相对路径，转换为绝对路径
                        if not os.path.isabs(abi_file):
                            abi_file = os.path.join(os.path.dirname(__file__), "..", abi_file)
                        
                        if os.path.exists(abi_file):
                            self.contract_abi = self.parse_abi(abi_file)
                        else:
                            print(f"警告: ABI文件不存在 {abi_file}")
                            self.contract_abi = None
                    else:
                        print("警告: 配置文件中未指定abi_file")
                        self.contract_abi = None
                else:
                    print("错误: 配置文件中未找到ProductTraceability配置")
                    self.contract_address = ""
                    self.contract_abi = None
            else:
                print(f"错误: 配置文件不存在 {config_path}")
                print("请创建product_traceability_config.json配置文件")
                self.contract_address = ""
                self.contract_abi = None
                
        except Exception as e:
            print(f"加载合约配置失败: {e}")
            self.contract_address = ""
            self.contract_abi = None

    @staticmethod
    def parse_abi(abifile):
        try:
            with open(abifile, 'r') as fd:
                data = fd.read()
                return json.loads(data)
        except FileNotFoundError:
            print(f"Error: The file {abifile} was not found.")
            return None
        except IOError:
            print(f"Error: An IOError occurred while reading the file {abifile}.")
            return None
        except json.JSONDecodeError:
            print(f"Error: The file {abifile} contains invalid JSON.")
            return None

    # 创建用户到区块链，并返回链上用户的地址，公钥，私钥
    def createUser(self, name):
        # 创建ecdsa
        data = self.cmd_account.create_ecdsa_account_task(name)
        print("register in blockchain:" ,data)
        return data

    def loadUser(self, privkey):
        return self.cmd_account.load_ecdsa_account(privkey)

    def format_address(self, address):
        """使用eth-utils将地址格式化为EIP-55校验和格式"""
        if not address or not isinstance(address, str):
            return address
        
        try:
            # 使用eth-utils的to_checksum_address函数
            return to_checksum_address(address)
        except Exception as e:
            print(f"地址格式化失败: {e}, 返回原地址: {address}")
            return address

    # 解析交易收据输出 - 使用官方DatatypeParser
    def parse_transaction_output(self, function_name,output_data):
        try:
            # 使用DatatypeParser解析输出
            parsed_output = self.data_parser.parse_receipt_output(function_name, output_data)
            print(f"函数 {function_name} 输出解析成功: {parsed_output}")
            
            return parsed_output
            
        except Exception as e:
            print(f"解析交易输出失败: {e}")
            return None

    # 上架商品 - 调用ProductTraceability合约（删除了productType、description、categoryName参数）
    def listProduct(self, privatekey, _productId, _productName, _price, _imageUrl, _parentTradeHash=""):
        print("调用ProductTraceability合约上架商品:", _productName)
        signer = Signer_ECDSA.from_privkey(privatekey)
        data = self.client.sendRawTransactionGetReceipt(
            self.contract_address,
            self.contract_abi,
            "listProduct",
            [_productId, _productName, _price, _imageUrl, _parentTradeHash],
            from_account_signer=signer
        )
        print('1111receipt data:', data['output'])
        # 解析返回的recordHash
        if data:
            parsed_output = self.parse_transaction_output('listProduct', data['output']) 

            if parsed_output and len(parsed_output) > 0:
                data['recordHash'] = parsed_output[0]  # 第一个返回值是recordHash
                print(f"上架成功，记录哈希: {parsed_output[0]}")
            else:
                data['recordHash'] = None
                print("警告: 无法解析recordHash")
        
        return data
    
    # 购买单个商品 - 调用ProductTraceability合约
    def buyProduct(self, privatekey, _listingHash, _buyer):
        print("调用ProductTraceability合约购买商品:", _listingHash)
        signer = Signer_ECDSA.from_privkey(privatekey)
        data = self.client.sendRawTransactionGetReceipt(
            self.contract_address,
            self.contract_abi,
            "buyProduct",
            [_listingHash, _buyer],
            from_account_signer=signer
        )
        
        # 解析返回的tradeHash
        if data:
            parsed_output = self.parse_transaction_output('buyProduct', data['output'])
            if parsed_output and len(parsed_output) > 0:
                data['tradeHash'] = parsed_output[0]  # 第一个返回值是tradeHash
                print(f"购买成功，交易哈希: {parsed_output[0]}")
            else:
                data['tradeHash'] = None
                print("警告: 无法解析tradeHash")
        
        return data
    
    # 批量购买商品 - 调用ProductTraceability合约
    def buyMultipleProducts(self, privatekey, _listingHashes, _buyer):
        print("调用ProductTraceability合约批量购买商品, 数量:", len(_listingHashes))
        signer = Signer_ECDSA.from_privkey(privatekey)
        data = self.client.sendRawTransactionGetReceipt(
            self.contract_address,
            self.contract_abi,
            "buyMultipleProducts",
            [_listingHashes, _buyer],
            from_account_signer=signer
        )
        
        # 解析返回的tradeHashes数组
        if data:
            parsed_output = self.parse_transaction_output('buyMultipleProducts', data['output'])
            if parsed_output and len(parsed_output) > 0:
                data['tradeHashes'] = parsed_output[0]  # 第一个返回值是tradeHashes数组
                print(f"批量购买成功，交易哈希列表: {parsed_output[0]}")
            else:
                data['tradeHashes'] = []
                print("警告: 无法解析tradeHashes")
        
        return data
    
    # 获取记录详情 - 调用ProductTraceability合约
    def getRecord(self, _recordHash):
        print("调用ProductTraceability合约获取记录详情:", _recordHash)
        result = self.client.call(self.contract_address, self.contract_abi, "getRecord", [_recordHash])
        
        # 解析getRecord的返回值
        if result:
            try:
                # 使用DatatypeParser解析getRecord的输出
                parsed_result = self.data_parser.parse_receipt_output('getRecord', result)
                
                # 将解析结果转换为更友好的格式
                if parsed_result and len(parsed_result) >= 12:  # 根据合约返回值数量调整
                    result_dict = {
                        'productId': parsed_result[0],
                        'productName': parsed_result[1], 
                        'recordType': parsed_result[2],
                        'seller': parsed_result[3],
                        'buyer': parsed_result[4],
                        'price': parsed_result[5],
                        'imageUrl': parsed_result[6],
                        'timestamp': parsed_result[7],
                        'isActive': parsed_result[8],
                        'parentTradeHash': parsed_result[9],
                        'relatedHash': parsed_result[10],
                        'isResale': parsed_result[11]
                    }
                    print(f"记录详情解析成功: {result_dict}")
                    return result_dict
                else:
                    print("警告: getRecord返回值解析失败")
                    return result
            except Exception as e:
                print(f"解析getRecord结果失败: {e}")
                return result
        
        return result
    
    # 获取用户记录 - 调用ProductTraceability合约
    def getUserRecords(self, _user):
        print("调用ProductTraceability合约获取用户记录:", _user)
        result = self.client.call(self.contract_address, self.contract_abi, "getUserRecords", [_user])
        
        if result:
            try:
                print(f"原始用户记录结果: {result}")
                
                # 直接处理元组或列表格式
                if isinstance(result, (tuple, list)) and len(result) > 0:
                    # 如果第一个元素是列表/元组，取第一个
                    if isinstance(result[0], (list, tuple)):
                        user_records = list(result[0])
                    else:
                        user_records = list(result)
                    
                    print(f"用户记录解析成功，数量: {len(user_records)}")
                    return user_records
                else:
                    # 尝试使用DatatypeParser
                    parsed_result = self.data_parser.parse_receipt_output('getUserRecords', result)
                    if parsed_result and len(parsed_result) > 0:
                        return parsed_result[0]
                    
            except Exception as e:
                print(f"解析getUserRecords结果失败: {e}")
        
        return []

    
    # 获取上架记录对应的交易记录 - 调用ProductTraceability合约
    def getListingTrades(self, _listingHash):
        print("调用ProductTraceability合约获取上架交易记录:", _listingHash)
        result = self.client.call(self.contract_address, self.contract_abi, "getListingTrades", [_listingHash])
        
        # 解析getListingTrades的返回值（字符串数组）
        if result:
            try:
                # 使用DatatypeParser解析getListingTrades的输出
                parsed_result = self.data_parser.parse_receipt_output('getListingTrades', result)
                
                if parsed_result and len(parsed_result) > 0:
                    listing_trades = parsed_result[0]  # 字符串数组
                    print(f"上架交易记录解析成功，数量: {len(listing_trades)}")
                    return listing_trades
                else:
                    print("警告: getListingTrades返回值解析失败")
                    return []
            except Exception as e:
                print(f"解析getListingTrades结果失败: {e}")
                return result
        
        return result
    
    # 获取用户可转售的商品 - 调用ProductTraceability合约
    def getUserResellableProducts(self, _user):
        print("调用ProductTraceability合约获取用户可转售商品:", _user)
        result = self.client.call(self.contract_address, self.contract_abi, "getUserResellableProducts", [_user])
        
        # 解析getUserResellableProducts的返回值（多个数组）
        if result:
            try:
                # 使用DatatypeParser解析getUserResellableProducts的输出
                parsed_result = self.data_parser.parse_receipt_output('getUserResellableProducts', result)
                
                if parsed_result and len(parsed_result) >= 4:
                    # getUserResellableProducts返回4个数组
                    result_dict = {
                        'tradeHashes': parsed_result[0],
                        'productIds': parsed_result[1],
                        'productNames': parsed_result[2],
                        'timestamps': parsed_result[3]
                    }
                    print(f"可转售商品解析成功，数量: {len(parsed_result[0])}")
                    return result_dict
                else:
                    print("警告: getUserResellableProducts返回值解析失败")
                    return {'tradeHashes': [], 'productIds': [], 'productNames': [], 'timestamps': []}
            except Exception as e:
                print(f"解析getUserResellableProducts结果失败: {e}")
                return result
        
        return result
    
    # 验证记录哈希 - 调用ProductTraceability合约
    def verifyRecordHash(self, _recordHash):
        print("调用ProductTraceability合约验证记录哈希:", _recordHash)
        result = self.client.call(self.contract_address, self.contract_abi, "verifyRecordHash", [_recordHash])
        
        # 解析verifyRecordHash的返回值
        if result:
            try:
                # 使用DatatypeParser解析verifyRecordHash的输出
                parsed_result = self.data_parser.parse_receipt_output('verifyRecordHash', result)
                
                if parsed_result and len(parsed_result) >= 3:
                    result_dict = {
                        'exists': parsed_result[0],
                        'recordType': parsed_result[1],
                        'isResale': parsed_result[2]
                    }
                    print(f"记录验证结果: {result_dict}")
                    return result_dict
                else:
                    print("警告: verifyRecordHash返回值解析失败")
                    return {'exists': False, 'recordType': 0, 'isResale': False}
            except Exception as e:
                print(f"解析verifyRecordHash结果失败: {e}")
                return result
        
        return result
    
    # 获取完整溯源链 - 调用ProductTraceability合约
    def getFullTraceChain(self, _startHash):
        print("调用ProductTraceability合约获取完整溯源链:", _startHash)
        result = self.client.call(self.contract_address, self.contract_abi, "getFullTraceChain", [_startHash])
        
        # 直接处理原始返回值，不使用DatatypeParser
        if result:
            try:
                print(f"原始溯源链结果: {result}")
                
                # 检查result是否是元组格式
                if isinstance(result, tuple) and len(result) >= 5:
                    # 直接解构元组
                    chain_hashes, chain_types, chain_addresses, chain_timestamps, chain_is_resale = result
                    
                    # 确保所有数组长度一致
                    if (len(chain_hashes) == len(chain_types) == len(chain_addresses) == 
                        len(chain_timestamps) == len(chain_is_resale)):
                        
                        # 格式化地址为EIP-55校验和格式
                        formatted_addresses = [self.format_address(addr) for addr in chain_addresses]
                        
                        result_dict = {
                            'chainHashes': list(chain_hashes),
                            'chainTypes': [int(t) for t in chain_types],
                            'chainAddresses': formatted_addresses,  # 使用格式化后的地址
                            'chainTimestamps': [int(ts) for ts in chain_timestamps],
                            'chainIsResale': [bool(r) for r in chain_is_resale]
                        }
                        print(f"溯源链解析成功，链长度: {len(chain_hashes)}")
                        print(f"格式化后的地址: {formatted_addresses}")
                        return result_dict
                    else:
                        print("警告: 溯源链数组长度不一致")
                        return self._empty_trace_chain()
                else:
                    print("警告: getFullTraceChain返回值格式不正确")
                    # 尝试使用DatatypeParser作为备选方案
                    try:
                        parsed_result = self.data_parser.parse_receipt_output('getFullTraceChain', result)
                        if parsed_result and len(parsed_result) >= 5:
                            # 同样格式化地址
                            formatted_addresses = [self.format_address(addr) for addr in parsed_result[2]]
                            
                            result_dict = {
                                'chainHashes': parsed_result[0],
                                'chainTypes': parsed_result[1],
                                'chainAddresses': formatted_addresses,  # 使用格式化后的地址
                                'chainTimestamps': parsed_result[3],
                                'chainIsResale': parsed_result[4]
                            }
                            return result_dict
                    except Exception as parser_error:
                        print(f"DatatypeParser也失败: {parser_error}")
                    
                    return self._empty_trace_chain()
                    
            except Exception as e:
                print(f"解析getFullTraceChain结果失败: {e}")
                return self._empty_trace_chain()
        
        return self._empty_trace_chain()
    
    def getStructuredTraceChain(self, start_hash):
        """获取结构化的完整溯源链"""
        print("调用ProductTraceability合约获取结构化溯源链:", start_hash)
        result = self.client.call(self.contract_address, self.contract_abi, "getStructuredTraceChain", [start_hash])
        
        if result:
            try:
                print(f"原始结构化溯源链结果: {result}")
                
                # 检查result是否是元组或列表格式
                if isinstance(result, (tuple, list)) and len(result) > 0:
                    # 如果第一个元素是列表/元组，取第一个
                    if isinstance(result[0], (list, tuple)):
                        steps_data = result[0]
                    else:
                        steps_data = result
                    
                    # 格式化返回的TraceStep数组
                    structured_steps = []
                    for step in steps_data:
                        if isinstance(step, (tuple, list)) and len(step) >= 10:
                            structured_step = {
                                'stepHash': step[0],
                                'stepType': int(step[1]),
                                'stepTypeName': step[2],
                                'seller': self.format_address(step[3]),
                                'buyer': self.format_address(step[4]),
                                'sellerRole': step[5],
                                'buyerRole': step[6],
                                'timestamp': int(step[7]),
                                'isResale': bool(step[8]),
                                'description': step[9]
                            }
                            structured_steps.append(structured_step)
                    
                    print(f"结构化溯源链解析成功，步骤数量: {len(structured_steps)}")
                    return structured_steps
                else:
                    # 尝试使用DatatypeParser作为备选方案
                    try:
                        parsed_result = self.data_parser.parse_receipt_output('getStructuredTraceChain', result)
                        if parsed_result and len(parsed_result) > 0:
                            structured_steps = []
                            for step in parsed_result[0]:
                                structured_step = {
                                    'stepHash': step[0],
                                    'stepType': int(step[1]),
                                    'stepTypeName': step[2],
                                    'seller': self.format_address(step[3]),
                                    'buyer': self.format_address(step[4]),
                                    'sellerRole': step[5],
                                    'buyerRole': step[6],
                                    'timestamp': int(step[7]),
                                    'isResale': bool(step[8]),
                                    'description': step[9]
                                }
                                structured_steps.append(structured_step)
                            return structured_steps
                    except Exception as parser_error:
                        print(f"DatatypeParser解析结构化溯源链失败: {parser_error}")
                    
                    print("警告: getStructuredTraceChain返回值格式不正确")
                    return []
                    
            except Exception as e:
                print(f"解析getStructuredTraceChain结果失败: {e}")
                return []
        
        return []
    
    #--------------------工具方法--------------------
    def _empty_trace_chain(self):
        """返回空的溯源链结构"""
        return {
            'chainHashes': [], 
            'chainTypes': [], 
            'chainAddresses': [], 
            'chainTimestamps': [], 
            'chainIsResale': []
        }

    # 保留原有的字符串解码方法作为备用
    def decode_string_from_hex(self, hex_string):
        """备用的字符串解码方法"""
        if hex_string.startswith('0x'):
            hex_string = hex_string[2:]
        
        # 检查长度是否足够（至少需要64字节用于偏移量和长度）
        if len(hex_string) < 128:
            raise ValueError("Hex string too short")
        
        # 跳过偏移量（前32字节，即64个字符）
        # 读取长度（接下来的32字节）
        length_hex = hex_string[64:128]
        length = int(length_hex, 16)
        
        if length == 0:
            return ""
        
        # 读取实际字符串数据
        data_start = 128
        data_end = data_start + (length * 2)  # 每个字节用2个十六进制字符表示
        
        if len(hex_string) < data_end:
            raise ValueError("Hex string too short for declared length")
        
        string_hex = hex_string[data_start:data_end]
        
        # 转换为字节然后解码为UTF-8字符串
        decoded_bytes = bytes.fromhex(string_hex)
        decoded_string = decoded_bytes.decode('utf-8')
        
        return decoded_string